/**
 * Copyright (C) 2012 João Francisco Biondo Trinca
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge,
 * publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 *
 * @author     João Francisco Biondo Trinca <wolfulus@gmail.com>
 * @copyright  2012 João Francisco Biondo Trinca <wolfulus@gmail.com>
 * @license    http://www.opensource.org/licenses/mit-license.html  MIT License
 *
 */

/**
 * NetBuffer classes
 */
var Buffer = require('buffer').Buffer;
var SlowBuffer = require('buffer').SlowBuffer;

/**
 * Converts the current buffer to a NetReader class
 */
Buffer.prototype.toNetReader = function () {
    return new NetReader(this);
};

/**
 * Converts the current buffer to a NetReader class
 */
SlowBuffer.prototype.toNetReader = function () {
    return new NetReader(this);
};

/**
 * Class constructor
 */
function NetReader(buffer) {

    // Stores the buffer contents
    this.buffer = buffer;

    // Stores the current buffer size
    this.offset = 0;
}

/**
 * Reads a char from the buffer
 * @param value
 */
NetReader.prototype.readInt8 = function () {
    var value = this.buffer.readInt8(this.offset);
    this.offset += 1;
    return value;
};

/**
 * Reads a byte from the buffer
 * @param value
 */
NetReader.prototype.readUInt8 = function () {
    var value = this.buffer.readUInt8(this.offset);
    this.offset += 1;
    return value;
};

/**
 * Reads a short from the buffer
 * @param value
 */
NetReader.prototype.readInt16 = function () {
    return this.readInt16BE();
};

/**
 * Reads a short from the buffer
 * @param value
 */
NetReader.prototype.readInt16BE = function () {
    var value = this.buffer.readInt16BE(this.offset);
    this.offset += 2;
    return value;
};

/**
 * Reads a short from the buffer
 * @param value
 */
NetReader.prototype.readInt16LE = function () {
    var value = this.buffer.readInt16LE(this.offset);
    this.offset += 2;
    return value;
};

/**
 * Reads an unsigned short from the buffer
 * @param value
 */
NetReader.prototype.readUInt16 = function () {
    return this.readUInt16BE();
};

/**
 * Reads an unsigned short from the buffer
 * @param value
 */
NetReader.prototype.readUInt16BE = function () {
    var value = this.buffer.readUInt16BE(this.offset);
    this.offset += 2;
    return value;
};

/**
 * Reads an unsigned short from the buffer
 * @param value
 */
NetReader.prototype.readUInt16LE = function () {
    var value = this.buffer.readUInt16LE(this.offset);
    this.offset += 2;
    return value;
};

/**
 * Reads an integer from the buffer
 * @param value
 */
NetReader.prototype.readInt32 = function () {
    return this.readInt32BE();
};

/**
 * Reads an integer from the buffer
 * @param value
 */
NetReader.prototype.readInt32BE = function () {
    var value = this.buffer.readInt32BE(this.offset);
    this.offset += 4;
    return value;
};

/**
 * Reads an integer from the buffer
 * @param value
 */
NetReader.prototype.readInt32LE = function () {
    var value = this.buffer.readInt32LE(this.offset);
    this.offset += 4;
    return value;
};

/**
 * Reads an unsigned integer from the buffer
 * @param value
 */
NetReader.prototype.readUInt32 = function () {
    return this.readUInt32BE();
};

/**
 * Reads an unsigned integer from the buffer
 * @param value
 */
NetReader.prototype.readUInt32BE = function () {
    var value = this.buffer.readUInt32BE(this.offset);
    this.offset += 4;
    return value;
};

/**
 * Reads an unsigned integer from the buffer
 * @param value
 */
NetReader.prototype.readUInt32LE = function () {
    var value = this.buffer.readUInt32LE(this.offset);
    this.offset += 4;
    return value;
};

/**
 * Reads a float from the buffer
 * @param value
 */
NetReader.prototype.readFloat = function () {
    return this.readFloatBE();
};

/**
 * Reads a float from the buffer
 * @param value
 */
NetReader.prototype.readFloatBE = function () {
    var value = this.buffer.readFloatBE(this.offset);
    this.offset += 4;
    return value;
};

/**
 * Reads a float from the buffer
 * @param value
 */
NetReader.prototype.readFloatLE = function () {
    var value = this.buffer.readFloatLE(this.offset);
    this.offset += 4;
    return value;
};

/**
 * Reads a double from the buffer
 * @param value
 */
NetReader.prototype.readDouble = function () {
    return this.readDoubleBE();
};

/**
 * Reads a double from the buffer
 * @param value
 */
NetReader.prototype.readDoubleBE = function () {
    var value = this.buffer.readDoubleBE(this.offset);
    this.offset += 8;
    return value;
};

/**
 * Reads a double from the buffer
 * @param value
 */
NetReader.prototype.readDoubleLE = function () {
    var value = this.buffer.readDoubleLE(this.offset);
    this.offset += 8;
    return value;
};

/**
 * Reads a null-terminated string from the buffer
 * @param value
 */
NetReader.prototype.readNtString = function () {
    var str = "";
    var s = 0;
    for (var i = this.offset; i < this.buffer.length; i++) {
        var ch = this.buffer[i];
        if (!ch) {
            s++;
            break;
        }
        str += String.fromCharCode(ch);
        s++;
    }
    this.offset += s;
    return str;
};

/**
 * Reads a string from the buffer
 * @param value
 */
NetReader.prototype.readString = function (bytes) {
    var str = "";
    var s = 0;
    for (var i = this.offset; i < this.buffer.length && i < this.offset + bytes; i++) {
        str += String.fromCharCode(this.buffer[i]);
        s++;
    }
    this.offset += s;
    return str;
};

/**
 * Reads a fixed-length string to the buffer (filled with zeros)
 * @param value
 */
NetReader.prototype.readFixedString = function (length) {
    var str = "";
    var s = 0;
    for (var i = this.offset; i < this.buffer.length && i < this.offset + length; i++) {
        var ch = this.buffer[i];
        if (!ch) {
            s++;
            break;
        }
        str += String.fromCharCode(ch);
        s++;
    }
    this.offset += length > s ? length : s;
    return str;
};

/**
 * Class export
 */
exports.NetReader = NetReader;